#include <unistd.h>
#include <vector>
#include <cassert>
#include <string>
#include <cstdio>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>

// 随机种子
#define MAKE_RAND() srand((unsigned int)time(nullptr) ^ getpid() ^ rand() ^ 43523)
#define SUB_NUM 4   //子进程数量


void download_mission()
{
    std::cout << getpid() << ":下载任务\n" << std::endl;
    sleep(1);
}

void IO_mission()
{
    std::cout << getpid() << ":访问外设任务\n" << std::endl;
    sleep(1);
}

void flush_mission()
{
    std::cout << getpid() << ":刷新任务\n" << std::endl;
    sleep(1);
}

typedef void(*func)();
void createMission(std::vector<func>& vec_mission)
{
    vec_mission.push_back(download_mission);
    vec_mission.push_back(IO_mission);
    vec_mission.push_back(flush_mission);
}


class Information   //管道与子进程信息
{
public:
    Information(const pid_t& id,const int& fd)
        :_id(id),_fd(fd)
    {
        char buffer[1024] = {0};
        snprintf(buffer,sizeof(buffer),"process-%d[pid(%d)-fd(%d)]",_size++,_id,_fd);
        _name = buffer;
    }
    std::string _name;  //管道与子进程的名字
    pid_t _id;  //子进程pid
    int _fd;    //管道入口(写端)
    static int _size;   //数量
};
int Information::_size = 0;

int readMission(int fd)
{
    int missionCode = 0;
    int ret = read(fd,&missionCode,sizeof(int));
    if(ret > 0)
    {
        return missionCode;
    }
    else 
    {
        return -1;
    }
}
void createSubprocess(std::vector<Information>& vec_information,
                    const std::vector<func>& vec_mission)
{
    std::vector<int> deleteFd;
    // 一个父进程，控制多个子进程(父进程写，子进程读)
    for(int i=0;i<SUB_NUM;i++)
    {
        int fds[2] = {0};
        int ret = pipe(fds);    //建立管道文件
        assert(ret == 0);

        pid_t id = fork();  //子进程
        assert(id >= 0);
        if(id == 0)
        {
            for(auto& e:deleteFd)
            {
                close(e);
            }
            close(fds[1]);
            //处理任务

            while(true)
            {
                int missionCode = readMission(fds[0]);

                if(missionCode >= 0 && missionCode < vec_mission.size())
                {
                    vec_mission[missionCode]();
                }
                else if(missionCode == -1)
                {
                    // 证明写端关闭
                    break;
                }
            }

            close(fds[0]);
            exit(0);
        }

        Information info(id,fds[1]);
        vec_information.push_back(info);    //将管道、子进程的信息，存入容器

        close(fds[0]);
        deleteFd.push_back(fds[1]);
    }
}

void sendMission(const Information& process,int missionIndex)
{
    std::cout << missionIndex << "任务发送给" << process._name << std::endl;
    int ret = write(process._fd,&missionIndex,sizeof(int));
    assert(ret == sizeof(int));
}

void waitSubprocess(const std::vector<Information>& vec_information)
{
    for(auto& e: vec_information)
    {
        int ret = waitpid(e._id,nullptr,0);
        assert(ret == e._id);

        std::cout << e._name << "已被回收" << std::endl;
    }
}


void parentProcessBegin(const std::vector<Information>& vec_information,
                        const std::vector<func>& vec_mission)
{
    // 向子进程发送任务
    int processNum = vec_information.size();    //子进程个数
    int missionNum = vec_mission.size();    //任务个数
    int TIME = 5;   //父进程要求子进程执行多少次任务


    bool forever = (TIME == 0 ? true : false);
    while(true)
    {
        int subIndex = rand() % processNum;
        int missionIndex = rand() % missionNum;

        sendMission(vec_information[subIndex],missionIndex);

        sleep(1);
        if(!forever)
        {
            --TIME;
            if(TIME == 0)
            {
                break;
            }
        }
    }

    // 将所有管道关闭
    for(auto& e:vec_information)
    {
        close(e._fd);
        waitpid(e._id,nullptr,0);
    }
}

int main()
{
    MAKE_RAND();

    std::vector<Information> vec_information;
    std::vector<func> vec_mission;

    createMission(vec_mission);
    createSubprocess(vec_information,vec_mission);



    parentProcessBegin(vec_information,vec_mission);    //开始执行任务

    //waitSubprocess(vec_information);    //回收子进程
    return 0;
}